#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>


#define	BACKLOG	 13
#define BUF_SIZE 1024

#define	MSG_STR	"Hello Client Welcome to Connect...!"



void print_usage(const char *program_name) 
{  
		printf("\n%s -- (2018.11.9)\n", program_name);  
        	printf(" Usage: %s -p <server_port>  [-h <server_use_help>]\n", program_name);  
		printf("	-p --port	the server listen port\n") ;
		printf("	-h --help	the server file how to use\n");  

		return ;
}  






int main( int argc, char **argv )
{
	int listen_fd,client_fd = -1 ;
	struct sockaddr_in	serv_addr ;
	struct	sockaddr_in	cli_addr ;
	socklen_t		cli_addr_len ;
	int 			rv = -1 ;
	char			buf[BUF_SIZE] ;
	int			opt = -1 ;	
	int			port = 0 ;
	pid_t			pid ;
	int			fd ;
	time_t 			timep;   
	struct tm 		*tim; 


	fd = open("server.log", O_RDWR|O_CREAT|O_APPEND, 0666) ;

	if(fd < 0)
	{
		printf("Open file failure:%s\n", strerror(errno) ) ;
		return -1 ;
	
	}





const char *short_opts = "p:h";  			//set  option


const struct option long_opts[] = 	{  

						{"help", no_argument, NULL, 'h'},  

				     		{ "port", required_argument, NULL, 'p'},  

					       {0, 0, 0, 0}  
			        	};  


while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1) 
	{
		switch (opt) 
		{
			case 'p':
				port = atoi(optarg);
				break ;

			case 'h':
				print_usage(argv[0]) ;
				return 0;
		
		
		}			
	

	}

	if( !port )
	{
		print_usage(argv[0]);
		return 0;
	
	}


	daemon(1,1) ;				//process running in   background
	dup2(fd, STDOUT_FILENO) ;		//stdout set to log
	listen_fd = socket(AF_INET, SOCK_STREAM, 0) ;
	if(listen_fd < 0)
	{
		printf("creat socket failure : %s \n", strerror(errno) ) ;
		return -2 ;
	
	}
	printf("creat socket suceeful, listen_fd descriptor[%d]\n", listen_fd) ;

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET ;
	serv_addr.sin_port = htons(port) ;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
	memset(&cli_addr, 0, sizeof(serv_addr));


	 int reuse = 1 ;
	 setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); //	Reuseaddr 

	if ( bind(listen_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ) < 0 )
	{
		printf("socket bind failure : %s\n", strerror(errno) ) ;
		goto cleanup ;
	}
	

	if ( listen(listen_fd ,BACKLOG) < 0 )
	{	
		printf("socket listen failure: %s\n", strerror(errno) ) ;
		goto cleanup ;
	}


	while(1)
	{
		printf("\n/********************************************************************/\n") ;	
		localtime(&timep) ;
		time(&timep);
		tim = localtime(&timep);


		printf("Server Start Work, Server port:%d, And Waiting The Client Connect ...\n", port) ;
		client_fd = accept(listen_fd,(struct sockaddr*) &cli_addr, &cli_addr_len) ; 
		if(client_fd < 0)
		{
			printf("accept failure: %s\n", strerror(errno)) ;
			return -3 ;
		}
		printf("accept succeful, client [%s:%d] \n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port) ) ;
		printf("\n			%d年%d月%d日 %d:%d:%d\n", (1900 + tim->tm_year), ( 1 + tim->tm_mon), tim->tm_mday, tim->tm_hour, tim->tm_min, tim->tm_sec); 

		pid = fork() ;
		if(pid < 0)
		{
			printf("Create PID failure:%s\n", strerror(errno)) ;
			continue ;
		}

		if(pid == 0)		// Chlid process read and write with client
		{
			
			close(listen_fd) ;

			printf("Child process is running\n") ;

			memset(buf, 0, sizeof(buf)) ;
			rv = read (client_fd, buf, sizeof(buf)) ;
			if(rv < 0)
			{
				printf("read from client failure: %s\n", strerror(errno)) ;
				goto cleanup ;
			}

			if(rv == 0)
			{
				printf("client connect failure!\n") ;
				exit(0) ;
			}




			printf("\n%d byte read from client[%d] : '%s' \n" ,rv, client_fd, buf) ;
			
			
		
			if (write(client_fd, MSG_STR, strlen(MSG_STR) ) < 0)
			{
				printf("write to client failed: %s\n", strerror(errno)) ;
				close(client_fd) ;
				continue ;
			}

			sleep(1) ;
			printf("close client socket[%d] and child process exit\n", client_fd);
			close(client_fd) ;

			exit(0) ;

			printf("If return there ,exit() failed\n") ;
			return -4 ;
		
			
		}
		
		
		else
		{
			close(client_fd) ;	// Parent process close client_fd and accpect a new client
			continue ;
		}


	}

cleanup:
	close(listen_fd) ;
	close(client_fd) ;
	



	return 0 ;
}

